#include<iostream>
#include<errno.h>
#include<unistd.h>
#include<pthread.h>
#include<string>
#include<cassert>
using namespace std;


// //解决策略：加锁保护:一定要保证加锁的力度越小越好。
// pthread_mutex_t mtx=PTHREAD_MUTEX_INITIALIZER;//pthread_mutex_t原生线程库提供的数据类型
// int tickets=10000;//临界资源

// //多线程抢票问题
// void *getTickets(void *args)
// {
//     while(true)
//     {
//         //加锁，未得到锁的线程阻塞等待
//         pthread_mutex_lock(&mtx);
//         //临界区
//         if(tickets>0)//1.判断的本质也是计算的一种
//         {
//             usleep(1000);
//             printf("%s:%d\n",(char*)args,tickets);
//             tickets--;//2.也可能出现问题
//             pthread_mutex_unlock(&mtx);
//         }
//         else
//         {
//             pthread_mutex_unlock(&mtx);
//             break;
//         }
//     }
//     return nullptr;
// }



// int main()
// {
//     pthread_t tid1,tid2,tid3;
//     //多线程抢票的逻辑
//     pthread_create(&tid1,nullptr,getTickets,(void*)"thread one");
//     pthread_create(&tid2,nullptr,getTickets,(void*)"thread two");
//     pthread_create(&tid3,nullptr,getTickets,(void*)"thread three");

//     pthread_join(tid1,nullptr);
//     pthread_join(tid2,nullptr);
//     pthread_join(tid3,nullptr);

//     return 0;
// }

#define THREAD_NUM 5

class ThreadData
{
public:
    ThreadData(string n,pthread_mutex_t *pm)
        :name(n),pmtx(pm)
        {}
public:
    string name;
    pthread_mutex_t *pmtx;
};


int tickets=10000;//临界资源

//多线程抢票问题
void *getTickets(void *args)
{
    ThreadData*td=(ThreadData*)args;
    while(true)
    {
        //加锁，未得到锁的线程阻塞等待
        int n=pthread_mutex_lock(td->pmtx);
        assert(n==0);
        //临界区
        if(tickets>0)//1.判断的本质也是计算的一种
        {
            usleep(1000);
            printf("%s:%d\n",td->name.c_str(),tickets);
            tickets--;//2.也可能出现问题
            n=pthread_mutex_unlock(td->pmtx);
            assert(n==0);
        }
        else
        {
            n=pthread_mutex_unlock(td->pmtx);
            assert(n==0);
            break;
        }
    }
    delete td;
    return nullptr;
}



int main()
{
    pthread_t t[THREAD_NUM];
    pthread_mutex_t mtx;
    pthread_mutex_init(&mtx,nullptr);
    for(int i=0;i<THREAD_NUM;i++)
    {
        string name="thread ";
        name+= to_string(i+1);
        ThreadData* td=new ThreadData(name,&mtx);
        pthread_create(t+i,nullptr,getTickets,(void*)td);
    }
    for(int i=0;i<THREAD_NUM;i++)
    {
        pthread_join(t[i],nullptr);
    }
    return 0;
}

